package q1.project.core.exception;

import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

/** 异常映射注册表 扫描所有带有 @ExceptionMapper 注解的异常类，建立异常到错误码的映射 参考 Graceful Response 的设计理念 */
@Component
public class ExceptionMappingRegistry implements ApplicationListener<ContextRefreshedEvent> {

  private static final Logger logger = LoggerFactory.getLogger(ExceptionMappingRegistry.class);

  private static final Map<Class<? extends Throwable>, ExceptionMapping> exceptionMappings =
      new HashMap<>();

  @Override
  public void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    scanExceptionMappings(context);
  }

  /** 扫描所有异常映射 */
  private void scanExceptionMappings(ApplicationContext context) {
    String[] beanNames = context.getBeanNamesForType(Object.class);
    for (String beanName : beanNames) {
      try {
        Object bean = context.getBean(beanName);
        Class<?> beanClass = bean.getClass();
        if (Throwable.class.isAssignableFrom(beanClass)) {
          @SuppressWarnings("unchecked")
          Class<? extends Throwable> throwableClass = (Class<? extends Throwable>) beanClass;
          checkExceptionMapper(throwableClass);
        }
      } catch (Exception e) {
        // 忽略无法处理的 Bean
      }
    }

    // 手动扫描常见的异常类
    checkExceptionMapper(BusinessException.class);
  }

  /** 检查异常类是否有 @ExceptionMapper 注解 */
  private void checkExceptionMapper(Class<? extends Throwable> exceptionClass) {
    ExceptionMapper mapper = exceptionClass.getAnnotation(ExceptionMapper.class);
    if (mapper != null) {
      registerMapping(exceptionClass, mapper.code(), mapper.msg());
    }
  }

  /** 注册异常映射 */
  public static void registerMapping(
      Class<? extends Throwable> exceptionClass, Integer code, String message) {
    ErrorCode errorCode = ErrorCode.getByCode(code);
    String finalMessage =
        message != null && !message.isEmpty()
            ? message
            : (errorCode != null ? errorCode.getMessage() : "操作失败");

    exceptionMappings.put(exceptionClass, new ExceptionMapping(code, finalMessage));
    logger.info("注册异常映射: {} -> code={}, message={}", exceptionClass.getName(), code, finalMessage);
  }

  /** 获取异常映射 */
  public static ExceptionMapping getMapping(Class<? extends Throwable> exceptionClass) {
    // 先查找精确匹配
    ExceptionMapping mapping = exceptionMappings.get(exceptionClass);
    if (mapping != null) {
      return mapping;
    }

    // 查找父类匹配
    Class<?> currentClass = exceptionClass.getSuperclass();
    while (currentClass != null && Throwable.class.isAssignableFrom(currentClass)) {
      mapping = exceptionMappings.get(currentClass);
      if (mapping != null) {
        return mapping;
      }
      currentClass = currentClass.getSuperclass();
    }

    return null;
  }

  /** 异常映射信息 */
  public static class ExceptionMapping {
    private final Integer code;
    private final String message;

    public ExceptionMapping(Integer code, String message) {
      this.code = code;
      this.message = message;
    }

    public Integer getCode() {
      return code;
    }

    public String getMessage() {
      return message;
    }
  }
}
